package br.com.news.dao.util;

import java.util.ArrayList;
import java.util.List;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.util.Log;
import br.com.news.dao.util.interfaces.IGenericDao;
import br.com.news.exception.DataException;
import br.com.news.modal.interfaces.IBaseBean;
import br.com.news.util.Constantes;

public abstract class GenericDao<T extends IBaseBean> implements IGenericDao<T> {

	protected SQLiteDatabase db;
	private NewsHelper newsHelper;

	/**
	 * Cria instancia GenericDao
	 * 
	 * @param context
	 */
	public GenericDao(Context context) {
		newsHelper = new NewsHelper(context, "NewsAndroid", RepositoryScript.VERSION_TWO);
		db = newsHelper.getWritableDatabase();
	}

	@Override
	public long salvar(T entity) throws DataException {
		long id = entity.getId();
		if (id != 0) {
			atualizar(entity);
		} else {
			id = inserir(entity);
		}
		return id;
	}

	@Override
	public void atualizar(T entity) throws DataException {
		try {
			ContentValues values = preencheValores(entity);
			String where = String.format("%s = ?", entity.nomePrimaryKey());
			String[] whereArgs = new String[] { String.valueOf(entity.getId()) };
			int count = db.update(entity.nomeTabela(), values, where, whereArgs);
			Log.i(Constantes.LOG, String.format("<GenericDao> Alterado %d registros na tabela %s", count, entity.nomeTabela()));
		} catch (Exception e) {
			throw new DataException(String.format("<GenericDao> Falha ao atualizar registro %d tabela %s", entity.getId(), entity.nomeTabela()), e);
		}
	}

	@Override
	public long inserir(T entity) throws DataException {
		try {
			ContentValues values = preencheValores(entity);
			long id = db.insert(entity.nomeTabela(), "", values);
			Log.i(Constantes.LOG, String.format("<GenericDao> Inserido o registro %d na tabela %s", id, entity.nomeTabela()));
			return id;
		} catch (Exception e) {
			throw new DataException(String.format("<GenericDao> Falha ao inserir registro  tabela %s", entity.nomeTabela()), e);
		}
	}

	@Override
	public int deletar(T entity) throws DataException {
		String where = String.format("%s = ?", entity.nomePrimaryKey());
		String[] whereArgs = new String[] { String.valueOf(entity.getId()) };
		int count = deletar(entity, where, whereArgs);
		return count;
	}

	@Override
	public int deletar(T entity, String where, String[] whereArgs) throws DataException {
		try {
			int count = db.delete(entity.nomeTabela(), where, whereArgs);
			Log.i(Constantes.LOG, String.format("<GenericDao> Deletou %d registros da tabela %s", count, entity.nomeTabela()));
			return count;
		} catch (Exception e) {
			throw new DataException(String.format("<GenericDao> Falha ao deletar registros tabela %s", entity.nomeTabela()), e);
		}
	}

	@Override
	public T findId(T entity) throws DataException {

		try {
			String where = String.format("%s = %d", entity.nomePrimaryKey(), entity.getId());
			Cursor c = db.query(true, entity.nomeTabela(), entity.nomeColunas(), where, null, null, null, null, null);

			if (c.getCount() > 0) {

				// Posicinoa no primeiro elemento do cursor
				c.moveToFirst();
				
				T t = preencheAtributos(c);
				c.close();
				return t;
			}
			c.close();

		} catch (Exception e) {
			throw new DataException(String.format("<GenericDao> Falha ao buscar o registro de Id %d tabela %s", entity.getId(), entity.nomeTabela()), e);
		}

		return null;

	}

	@Override
	public List<T> findAll(T entity) throws DataException {

		try {

			Cursor c = db.query(entity.nomeTabela(), entity.nomeColunas(), null, null, null, null, null, null);

			if (c.moveToFirst()) {
				List<T> t = preencheAtributosList(c);
				c.close();
				return t;
			} else {
				c.close();
				return new ArrayList<T>();
			}

		} catch (Exception e) {
			throw new DataException(String.format("<GenericDao> Falha ao buscar todos os registros da tabela %s", entity.nomeTabela()), e);
		}

	}

	@Override
	public List<T> findWhere(T entity, String where, String[] whereArgs, String orderBy) throws DataException {
		try {
			Cursor c = 	db.query(entity.nomeTabela(), entity.nomeColunas(), where, whereArgs, null, null, orderBy);

			if (c.moveToFirst()) {
				List<T> t = preencheAtributosList(c);
				c.close();
				return t;
			} else {
				c.close();
				return new ArrayList<T>();
			}

		} catch (Exception e) {
			throw new DataException(String.format("<GenericDao> Falha ao buscar os registros da tabela %s pela consulta %s", entity.nomeTabela(), where), e);
		}
	}

	public abstract T preencheAtributos(Cursor c);

	public abstract List<T> preencheAtributosList(Cursor c);

	public abstract ContentValues preencheValores(T entity);

	/**
	 * fechar conex�o
	 * 
	 */
	@Override
	public void fechar() {
		if (newsHelper != null) {
			newsHelper.close();
			Log.i(Constantes.LOG, "<GenericDao> Conexão com o banco finalizada!");
		}
	}

}
